'''
TODO web自动化测试框架
1、主流的测试工具：
              QTP：            收费
              Selenium：       只能做 UI-web 自动化测试，其他功能没有，免费（硒）
                               开源、跨平台、支持多种语言（python/java/c）、支持常见浏览器（谷歌/火狐/ie/edge/safari/欧朋）
              Robot framework：
2、Selenium发展史：
               1.0：
                   Selenium IDE： 录制并回放测试
                   Selenium Grid：分布式集成操作
                   Selenium RC： 使用js模拟浏览器，通过输出js实现浏览器操作，不支持弹窗、下载自签证书和文件等（核心组件）
               2.0：
                   1.0 + WebDriver（核心组件）
                   2.0 是过渡版本，主要是使用 WebDriver 替换 RC
               3.0：
                   去掉 Selenium RC
                   所有浏览器需安装 Selenium 框架外，还需安装浏览器对应的驱动程序
3、环境搭建：
          ① python 开发环境（pycharm）
          ② 安装 Selenium 包（pip工具安装）
                                         安装：pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy
                                         查看：pip list
          ③ 安装浏览器（谷歌/火狐）
                              查看版本：打开火狐浏览器 - 右上角三条横线 - 帮助 - 关于
          ④ 安装浏览器驱动
                        https://github.com/mozilla/geckodriver/releases/tag/v0.35.0
          ⑤ 详细操作：
                    11、cmd - where python （获取python解释器上一层文件路径）
                    12、打开任一文件夹 - 地址栏粘贴路径 - 确认python解释器存在即可
                    13、将浏览器驱动 geckodriver.exe 剪切到python解释器同一路径下
4、元素定位：
          ① 说明：计算机无法像人一样，所见即所得，因此需要通过页面内元素对应的代码中的相关特征来定位及操作元素
                 标签名/属性：属性值
                 当页面内有多个元素的特征值是相同的时候，定位元素的方法执行时，默认只会获取第一个符合要求的特征对应的元素
                 因此，定义元素时，需尽量保证使用的特征值能代表目标元素在当前页面内的唯一性
                 By.ID等：在使用PO涉及模式，封装代码结构时需要使用
          ② 定位方法：
                   11、id定位：
                             概念：通过元素的id属性来定位
                                  html规定id属性在整个html文档中必须是唯一的（当元素存在id属性时，优先使用id方法定位元素）
                             方法： element = driver.find_element(By.ID, id)
                   12、name定位：
                              概念：html文档中name的属性值可以重复
                              方法： element = driver.find_element(By.NAME, id)
                   13、class_name定位：
                                    概念：根据class属性值定位
                                         如果class有多个属性值，只能使用其中一个（如：email dzyxa，只能用 email或 dzyxa）
                                    方法：element = driver.find_element(By.CLASS_NAME, class_name)
                   14、tag_name定位：
                                  概念：通过标签名定位
                                       html本质就是由不同的tag组成，每一种标签在页面会存在多个，不方便精准定位，因此很少使用
                                  方法：element = driver.find_element(By.TAG_NAME, tag_name)
                   15、link_text定位：
                                   概念:专门用来定位超链接元素(<a>标签</a>),并且通过超链接文本内容来定位元素
                                   方法:element = driver.find_element(By.LINK_TEXT, link_text)
                   16、partial_link_text定位：
                                           概念:专门用来定位超链接元素,只需要传入超链接的部分文本信息,但需要保证文本信息的唯一性
                                           方法:element = driver.find_element(By.PARTIAL_LINK_TEXT, link_text)
                   17、定位一组元素：
                                 概念：元素定位方法带有 "s"，执行结果返回的是列表类型数据，里面的数据是多个元素对象
                                 方法：elements = driver.find_element(By.name, "AAA")
                   18、XPath定位：
                               a 概念：xml是一种标记语言，用于数据的存储和传递，后缀以.xml结尾（html是xml的一种实现）
                               b 定位策略：
                                     可以在浏览器工具中组装策略值，验证后再放入代码中使用
                                           路径：
                                               绝对路径：以/html根节点开始
                                                       /html/body/div/fieldset/p[1]/input
                                                       方法：
                                               相对路径：以//开始                               目标元素 - 右键 - 检查
                                                       //input 或 //*                        html页面，选中当前行 - 右键 - 复制 - Xpath
                                           利用元素属性：                                      外层先用单引号，再粘贴过来
                                                       语法1：//input[@属性=属性值]
                                                       语法2：//*[@属性=属性值]                与class_name方法不同，如果使用多个值的class属性，需传入全部的属性值
                                           属性与逻辑结合：
                                                       说明：解决元素之间存在多个相同属性的重名问题
                                                       格式：//*[@name="tell" and @class="tell"]
                                           层级与属性结合：
                                                       说明：通过元素自身的信息无法直接定位该元素时，可以先定位到其父级元素，再找到该元素
                                                       格式：//*[@id='p1']/input
                                                           //form//*[@id="user"]      （祖辈和后代的关系）
                               c 方法：element = driver.find_element(By.XPATH, xpath定位策略)
                               d 延伸：
                                     //*[text()='xxx']               文本内容是xxx的元素  （要求全部文本内容）
                                     //*[contains(@属性, 'xxx')]      属性中包含xxx的元素  （属性值的部分内容）
                                     //*[starts-with(@属性, 'xxx')]   属性以xxx开头的元素
                   19、CSS定位：
                             css：一种语言，描述html页面的显示样式
                             css定位比xpath效率高
                             定位策略：
                                    id 选择器：
                                             说明：根据元素的id属性来选择
                                             格式：#属性值
                                    class 选择器：
                                                说明：根据元素的class属性来选择 （与class_name方法不同，如果使用多个值的class属性，需传入全部的属性值）
                                                格式：.属性值
                                    元素 选择器：
                                              说明：也叫标签选择器，根据元素的标签名选择
                                              格式：标签名
                                    属性 选择器：
                                              说明：根据元素的属性名和值来选择
                                              格式：
                                                  语法1：[属性名="属性值"]
                                                  语法2：标签名[属性名="属性值"]
                                    层级 选择器：
                                              说明：根据元素的父子关系来选择
                                              格式：
                                                  语法1：p[id='p1']>input    定位指定p元素下的直接子元素input
                                                        或：#p1>input
                                                  语法2：p[id='p1'] input    定位指定p元素下的后代元素 input
                                                        或：#p1 input
                                              延伸：
                                                  input[id^='p']      id属性以p开头的元素
                                                  input[id$='p']      id属性以p结尾的元素
                                                  input[id*='p']      id属性包含p的元素
                             方法：element = driver.find_element(By.CSS_SELECTOR, CSS定位策略)
5、动态模板：
          见 2-3 第二篇python
6、元素操作：
          常见方法：
                 click()
                 send_keys()
                 clear()
7、浏览器操作：
            通过调用 selenium 的 API 来实现浏览器操作
                   常用方法：
                          maximize_window()                 最大化浏览器窗口 -> 模拟浏览器最大化按钮
                          set_window_size(width, height)    设置浏览器窗口大小 -> 设置浏览器宽、高（像素点）
                          set_window_position(x, y)         设置浏览器窗口位置 -> 设置浏览器位置（像素点）      ( web 和 APP 都是以屏幕左上角为原点 ）
                          back()                            后退 -> 模拟浏览器后退按钮
                          forward()                         前进 -> 模拟浏览器前进按钮
                          refresh()                         刷新 -> 模拟浏览器F5刷新                       （重新向服务器发起当前页面的请求）
                          close()                           关闭当前窗口 -> 模拟点击浏览器关闭按钮            （没有切换页面时，关闭的是原始页面）
                          quit()                            关闭浏览器驱动对象 -> 关闭所有程序启动窗口
                          title                             获取页面 title                                (title 和 current_url 可以作断言使用）
                          current_url                       获取当前页面 url

8、获取元素信息：
             常用方法：
                    size                        返回元素大小                                        （判断页面元素布局尺寸是否合理使用）
                    text                        获取元素的文本                                      （用于切换页面后，可用作断言使用）
                    get_attribute("属性名")      获取属性值，传递的参数为元素的属性名
                    is_displayed()              判断元素是否可见                                     （元素不显示不意味着一定无法定位）
                    is_enabled()                判断元素是否可用                                     （多用于判断元素是否可进行交互）
                    os_selected()               判断元素是否选中，用来检查复选框或单选按钮是否被选中        （如购物车页面，不全选商品，不让结算）

'''